#ifndef _MISCMGR_H
#define _MISCMGR_H

class World;
class Player;
class Item;

struct CharRaceEntry;
struct CharClassEntry;

enum HIGHGUID_TYPE
{
	HIGHGUID_TYPE_PLAYER			= 0x00000000,
	HIGHGUID_TYPE_CORPSE			= 0x30000000,
	HIGHGUID_TYPE_ITEM				= 0x40000000,
	HIGHGUID_TYPE_CONTAINER			= 0x50000000,
	HIGHGUID_TYPE_DYNAMICOBJECT		= 0x60000000,
	HIGHGUID_TYPE_WAYPOINT			= 0x10000000,
	HIGHGUID_TYPE_TRANSPORTER		= 0x1FC00000,
	HIGHGUID_TYPE_GAMEOBJECT		= 0xF1100000,
	HIGHGUID_TYPE_UNIT				= 0xF1300000,
	HIGHGUID_TYPE_PET				= 0xF1400000,
	HIGHGUID_TYPE_VEHICLE			= 0xF1500000,

	HIGHGUID_TYPE_MASK				= 0xFFF00000,
	LOWGUID_ENTRY_MASK				= 0x00FFFFFF,
};

struct PlayerCreateInfo
{
	ui32 id;
	ui32 race;
	ui32 factiontemplate;
	ui32 clas;
	ui32 map;
	ui32 zone;
	float x, y, z;
	ui32 displayid;
	ui32 strength, agility, stamina, intellect, spirit, health, mana, rage, focus;
	ui32 energy, attackpower, mindamage, maxdamage, introid;
};

struct PlayerInfo
{
	ui32 guid;
	ui32 accountid;
	char* name;
	ui8 team;
	ui8 gender;
	PlayerCreateInfo* info;
};

#pragma pack(1)

struct SocketInfo 
{
	ui32 SocketColor;
	ui32 Unk;
};

struct ItemSpell
{
	ui32 Id;
	ui32 Trigger;
	i32 Charges;
	i32 Cooldown;
	ui32 Category;
	i32 CategoryCooldown;
};

struct ItemDamage
{
	float Min;
	float Max;
	ui32 Type;
};

struct ItemStat
{
	ui32 Type;
	i32 Value;
};

struct ItemInfo
{
	ui32 ItemId;
	ui32 Class;
	ui32 SubClass;
	ui32 unknown_bc;
	char* Name1;
	char* Name2;
	char* Name3;
	char* Name4;
	ui32 DisplayInfoID;
	ui32 Quality;
	ui32 Flags;
	ui32 Faction;
	ui32 BuyPrice;
	ui32 SellPrice;
	ui32 InventoryType;
	ui32 AllowableClass;
	ui32 AllowableRace;
	ui32 ItemLevel;
	ui32 RequiredLevel;
	ui32 RequiredSkill;
	ui32 RequiredSkillRank;
	ui32 RequiredSpell;
	ui32 RequiredPlayerRank1;
	ui32 RequiredPlayerRank2;
	ui32 RequiredFaction;
	ui32 RequiredFactionStanding;
	ui32 Unique;
	ui32 MaxCount;
	ui32 ContainerSlots;
	ui32 itemstatscount;
	ItemStat Stats[10];
	ui32 ScalingStatsEntry;
	ui32 ScalingStatsFlag;
	ItemDamage Damage[2];
	ui32 Armor;
	ui32 HolyRes;
	ui32 FireRes;
	ui32 NatureRes;
	ui32 FrostRes;
	ui32 ShadowRes;
	ui32 ArcaneRes;
	ui32 Delay;
	ui32 AmmoType;
	float  Range;
	ItemSpell Spells[5];
	ui32 Bonding;
	char * Description;
	ui32 PageId;
	ui32 PageLanguage;
	ui32 PageMaterial;
	ui32 QuestId;
	ui32 LockId;
	ui32 LockMaterial;
	ui32 Field108;
	ui32 RandomPropId;
	ui32 RandomSuffixId;
	ui32 Block;
	ui32 ItemSet;
	ui32 MaxDurability;
	ui32 ZoneNameID;
	ui32 MapID;
	ui32 BagFamily;
	ui32 TotemCategory;
	SocketInfo Sockets[3];
	ui32 SocketBonus;
	ui32 GemProperties;
	i32 DisenchantReqSkill;
	ui32 ArmorDamageModifier;
	ui32 ExistingDuration;
	ui32 ItemLimitCategory;
};

#pragma pack()

struct Skilllineentry
{
	ui32 id;
	ui32 type;
	ui32 skillCostsID;
	char*  Name;
};

struct SkillLineEntry
{
	Skilllineentry* skillentry;
	ui32 level;
	ui32 max_level;
};

struct CreatureBasic
{
	ui32 entry;
	char* name;
	char* subname;
	char* info_str;
	ui32 type;
	ui32 family;
	ui32 displayid1;
	ui32 displayid2;
	ui32 displayid3;
	ui32 displayid4;
	ui32 rank;
};

struct CreatureDetails
{
	ui32 entry;
	ui32 minlvl;
	ui32 maxlvl;
	ui32 minhealth;
	ui32 maxhealth;
	ui32 faction;
	ui32 npcflags;
	float scale;
	ui32 mainhand;
	ui32 offhand;
	ui32 rangedhand;
};

struct WorldMapInfo
{
	ui32 id;
	ui32 screen;
	ui32 type;
	ui32 maxplayers;
	ui32 minlevel;
	ui32 minlevel_heroic;
	float repopx, repopy, repopz;
	ui32 repopmap;
	char* name;
	ui32 flags;
	ui32 cooldown;
	ui32 lvl_mod_a;
	ui32 reqquest;
	ui32 reqitem;
	ui32 heroic_key1;
	ui32 heroic_key2;
	ui32 viewingdistance;
	ui32 checkpoint;
};

struct GossipText
{
	ui32 id;
	char* text;
};

struct TextRelation
{
	ui32 npcentry;
	ui32 textid;
};

struct TrainerSpell
{
	ui32 id;
	ui32 level;
	ui32 price;
	ui32 required_skill;
	ui32 required_skill_rank;
	ui32 required_spell;
};

struct Trainer
{
	ui32 entry;
	std::set<TrainerSpell*> m_trainerspells;
};

struct GuardPoiEntry
{
	float x, y;
	char* text;
	ui32 id;
};

struct GuardPoi
{
	ui32 entry;
	map<ui32, GuardPoiEntry*> m_pois;
};

struct GameObjectInfo
{
	ui32 entry, displayid;
	char* name;
	ui32 type;
	ui32 spellfocus;
};

struct WorldZoneArea
{
	ui32 id, mapref, arearef;
	char* name;
	float x1, y1, x2, y2;
	ui32 virtualmap;
	ui32 dungeonmap;
};

struct GameObjectTeleport
{
	ui32 id, spellfocus, casttime, mapid;
	float x, y, z;
};

#pragma pack(1)

struct AreaEntry
{
	ui32 AreaId;
	ui32 mapId;
	ui32 ZoneId;
	ui32 explorationFlag;
	ui32 AreaFlags;
	ui32 EXP;
	ui32 level;
	char* name;
	ui32 category;
};

struct AreaGroup
{
	ui32 GroupId;
	ui32 AreaIds[7];
};

struct SpellCastEntry
{
	ui32 entry;
	ui32 casttime;
};

struct _WayPointEntry
{
	ui32 index;
	float x, y, z;
};

struct WayPointEntry
{
	ui32 entry;
	unordered_set<_WayPointEntry*> waypoints;
};

struct RecallEntry
{
	ui32 id;
	char* name;
	ui32 mapid;
	float x, y, z;

	// Custom part
	RecallEntry();
	void TeleportPlayer(Player* target);
	prop<Landmark, RecallEntry, false> Position;
	Landmark GetPosition();
	void SetPosition(Landmark&);
};

#pragma pack()

class DLL_EXPORT MiscManager : public Single<MiscManager>
{
	friend class World;
	typedef stdext::hash_map<ui32, PlayerCreateInfo*> PlayerCreateInfoStorage;
	typedef stdext::hash_map<ui32, PlayerInfo*> PlayerInfoStore;
	typedef stdext::hash_map<ui32, Trainer*> TrainerStore;
	typedef map<ui32, GuardPoi*> GuardPoiStore;
	typedef stdext::hash_map<ui32, WayPointEntry*> WayPointStorage;
	Mutex m_playerinflock;
	PlayerInfoStore PlayerInfos;
	WayPointStorage WayPointStore;
	SQLStorage<PlayerCreateInfo> PlayerInfoStorage;
	SQLStorage<ItemInfo> ItemInfoStorage;
	SQLStorage<WorldMapInfo> WorldMapInfoStorage;
	SQLStorage<CreatureBasic> CreatureBasicStorage;
	SQLStorage<CreatureDetails> CreatureDetailsStorage;
	SQLStorage<GossipText> GossipTextStorage;
	SQLStorage<GameObjectInfo> GameObjectInfoStorage;
	SQLStorage<Quest> QuestInfoStorage;
	SQLStorage<TextRelation> NPCTextStorage;
	SQLStorage<RecallEntry> RecallStorage;
	SQLStorage<GameObjectTeleport> GameObjectTeleportStorage;
	TrainerStore TrainerStorage;
	GuardPoiStore GuardPoiStorage;
	set<Player*> m_players;
	stdext::hash_map<ui64, Item*> ItemStorage;
	void LoadPlayers();
	void LoadDBC();
	void LoadItems();
	void LoadQuests();
	void LoadMaps();
	void LoadNpcs();
	void LoadGameObjects();
	ui64 m_playerguids;
	Mutex m_playerguidlock;
	ui32 m_itemguids;
	Mutex m_itemguidlock;
	MiscManager() : m_itemguids(0), m_playerguids(0)
	{
	}
public:

	///////////////////////////////////////////////////////////////
	//	Playerstuff
	//
	PlayerCreateInfo* FindPlayerCreateInfo(ui8 race, ui8 clas);
	Player* CreatePlayer();
	PlayerInfo* GetPlayerInfo(ui64 guid);
	PlayerInfo* GetPlayerInfo(const char* name);
	void AddPlayerInfo(PlayerInfo* inf);
	void AddPlayer(Player* plr);
	void RemovePlayer(const char* name);
	void RemovePlayer(ui64 guid);
	void RemovePlayer(Player* plr);
	Player* GetPlayer(const char* name);
	Player* GetPlayer(ui64 guid);
	RecallEntry* GetRecallLocation(const char* name);
	RecallEntry* GetRecallLocation(ui32 id);
	void AddRecallLocation(RecallEntry* location);
	Mutex m_playerslock;

	//////////////////////////////////////////////////////////////
	//	Itemstuff
	//
	ItemInfo* GetItemInfo(ui32 id);
	Item* CreateItem(ui32 id, Player* owner = NULL);
	Item* CreateExistantItem(ui32 lowguid);
	void RemoveItem(ui64 guid);
	Item* GetItem(ui64 guid) { return ItemStorage[guid]; }

	//////////////////////////////////////////////////////////////
	//	CreatureStuff
	//
	CreatureBasic* GetCreatureBasic(ui32 id) { return CreatureBasicStorage.LookupEntry(id); }
	CreatureDetails* GetCreatureDetails(ui32 id) { return CreatureDetailsStorage.LookupEntry(id); }
	GossipText* GetGossipText(ui32 id) { return GossipTextStorage.LookupEntry(id); }
	void LoadTrainers();
	Trainer* GetTrainer(ui32 id) { return TrainerStorage[id]; }
	void LoadGuards();
	void LoadWayPoints();
	GuardPoi* GetGuardPoi(ui32 entry) { return GuardPoiStorage[entry]; }
	TextRelation* GetTextRelation(ui32 entry) { return NPCTextStorage.LookupEntry(entry); }
	WayPointEntry* GetWayPoints(ui32 entry) { return WayPointStore[entry]; }

	/////////////////////////////////////////////////////////////
	//	GameObjectStuff
	//
	GameObjectInfo* GetGameObjectInfo(ui32 entry) { return GameObjectInfoStorage.LookupEntry(entry); }
	GameObjectTeleport* GetGameObjectTeleport(ui32 entry) { return GameObjectTeleportStorage.LookupEntry(entry); }
	void ReloadGameObjectTeleport();

	/////////////////////////////////////////////////////////////
	//	QuestStuff
	//
	Quest* GetQuestInfo(ui32 entry) { return QuestInfoStorage.LookupEntry(entry); }
};

#define miscmgr MiscManager::getSingle()

#endif